//=====================================================================
//    COPYRIGHT(C) Innobeam
//    ALL RIGHTS RESERVED
//=====================================================================
//Filename    : LCD_Ctrl.v
//Created On  : 2018-12-21
//Author      : HAOYU.XIAO
//Description : LCD reset,LCD init,lcd updata,lcd display off
//Include     : LCD_Init,LCD_Updata,LCD_Displayoff
//Modification: 
//=====================================================================
module LCD_Ctrl(
	iClk,
	iRst_n,
	
	OLCD_RST,		
	oLCD_DC	,		
	oLCD_CTRL,		
	ovLCD_SPI_TxData,
	oLCD_SPI_Start,	

	ivLCD_SPI_RxData,
	iLCD_SPI_Done,
	
	iMoveStop,
	
	iComm_stateTrOut,
	ivDisplay_state	,
	ivGantry		,	
	ivCollimator	,	
	ivSwing			,	
	ivMLCX			,	
	ivMLCX1			,	
	ivMLCX2			,	
	ivJAWY			,
	ivJAWY1			,	
	ivJAWY2			,		
	ivCouch_VRT		,	
	ivCouch_LAT		,	
	ivCouch_LNG		,	
	ivCouch_LNG_PLAN,
	
	iLCDInit,
	iLCDUpdate,
	iLCDDisplayOn,
	iLCDDisplayOff,
	oLCDUpdateDone,
	oLCDInitDone,
	oLCDDisPlayOnDone,
	oLCDDisPlayOffDone
	);
//========================================================================
//    parameter
//========================================================================
//states define for FSM	
parameter     	LCD_RESET			= 4'b0000;
parameter     	LCD_INIT 			= 4'b0001;
parameter     	LCD_WAIT 			= 4'b0010;
parameter     	LCD_DISPLAYON		= 4'b0100;
parameter     	LCD_UPDATA 			= 4'b1000;
parameter       LCD_DISPLAYOFF		= 4'b1001;

//========================================================================
//    port
//========================================================================	
	input 				iClk;
	input 				iRst_n;
	
	output				OLCD_RST;		
	output				oLCD_DC;	
	output				oLCD_CTRL;		
	output	[7:0]		ovLCD_SPI_TxData;
	output				oLCD_SPI_Start;
	
	input	[7:0]		ivLCD_SPI_RxData;
	input				iLCD_SPI_Done;
	
	input				iMoveStop;
	
	input				iComm_stateTrOut;
	input	[4:0]		ivDisplay_state;	
	input	[15:0]		ivGantry;			
	input	[15:0]		ivCollimator;		
	input	[15:0]		ivSwing;
	input	[15:0]		ivMLCX;		
	input	[15:0]		ivMLCX1;				
	input	[15:0]		ivMLCX2;	
	input	[15:0]		ivJAWY;	
	input	[15:0]		ivJAWY1;				
	input	[15:0]		ivJAWY2;					
	input	[15:0]		ivCouch_VRT;			
	input	[15:0]		ivCouch_LAT;			
	input	[15:0]		ivCouch_LNG;	
	input	[15:0]		ivCouch_LNG_PLAN;
	
	input				iLCDInit;
	input				iLCDUpdate;
	input				iLCDDisplayOn;
	input				iLCDDisplayOff;
	output				oLCDUpdateDone;
	output				oLCDInitDone;	
	output				oLCDDisPlayOnDone;
	output				oLCDDisPlayOffDone;
//========================================================================
//    signal
//========================================================================	
			
	reg		[7:0]		ovLCD_SPI_TxData;
	reg					oLCD_SPI_Start;
	reg					OLCD_RST;
	reg					oLCD_DC;				
	reg					oLCD_CTRL;						

	wire 	[7:0]		wvLCD_SPI_TxData_Init;
	wire 				wLCD_SPI_Start_Init;
	wire				wLCD_RST;
	
	reg 				rLCD_Start_Init;
	wire 				wLCD_Init_Done;
	wire				wLCD_DC_Init;
	
	reg 				rLCD_Start_Update;
	wire				wLCD_Updata_Done;
	wire				wLCD_DC_Updata;
	wire	[7:0]		wvLCD_SPI_TxData_Updata;
	wire				wLCD_SPI_Start_Updata;
	
	reg 				rLCD_Start_DisplayOff;
	wire				wLCD_DisplayOff_Done;
	wire				wLCD_DC_DisplayOff;
	wire	[7:0]		wvLCD_SPI_TxData_DisplayOff;
	wire				wLCD_SPI_Start_DisplayOff;
	
	reg 				rLCD_Start_DisplayOn;
	wire				wLCD_DisplayOn_Done;
	wire				wLCD_DC_DisplayOn;
	wire	[7:0]		wvLCD_SPI_TxData_DisplayOn;
	wire				wLCD_SPI_Start_DisplayOn;

	reg 	[3:0]		rvState;

	wire	[4:0]		wvColumn;
	wire	[3:0]		wvRow;
	reg		[1:0]		rvStage;
	reg					rType;
	wire	[7:0]		wvAscii;	
	wire	[15:0]		wvFontcolor;
	wire	[15:0]		wvBGcolor;

//========================================================================
//	assign oEPDReady=wEPD_Init_Done;
//	assign	wEPD_Start_Init=iDataUpdate;
	assign  oLCDInitDone = wLCD_Init_Done;
	assign	oLCDUpdateDone = wLCD_Updata_Done;
	assign 	oLCDDisPlayOnDone = wLCD_DisplayOn_Done;
	assign  oLCDDisPlayOffDone = wLCD_DisplayOff_Done;
//========================================================================
	LCD_INIT LCD_INIT_inst(
		.iClk(iClk),
		.iRst_n(iRst_n),
		
		.ovLCD_SPI_TxData(wvLCD_SPI_TxData_Init),
		.oLCD_SPI_Start(wLCD_SPI_Start_Init),
		.oLCD_DC(wLCD_DC_Init),
		.ivLCD_SPI_RxData(),
		.iLCD_SPI_Done(iLCD_SPI_Done),
		
		.iLCD_Start_Init(rLCD_Start_Init),
		.oLCD_Init_Done(wLCD_Init_Done)
	);
	LCD_DISPLAYON LCD_DISPLAYON_inst(
		.iClk(iClk),
		.iRst_n(iRst_n),
		
		.ovLCD_SPI_TxData(wvLCD_SPI_TxData_DisplayOn),
		.oLCD_SPI_Start(wLCD_SPI_Start_DisplayOn),
		.oLCD_DC(wLCD_DC_DisplayOn),
		.ivLCD_SPI_RxData(),
		.iLCD_SPI_Done(iLCD_SPI_Done),
		
		.iLCD_Start_DisplayOn(rLCD_Start_DisplayOn),
		.oLCD_DisplayOn_Done(wLCD_DisplayOn_Done)
	);
	LCD_DISPLAYOFF LCD_DISPLAYOFF_inst(
		.iClk(iClk),
		.iRst_n(iRst_n),
		
		.ovLCD_SPI_TxData(wvLCD_SPI_TxData_DisplayOff),
		.oLCD_SPI_Start(wLCD_SPI_Start_DisplayOff),
		.oLCD_DC(wLCD_DC_DisplayOff),
		.ivLCD_SPI_RxData(),
		.iLCD_SPI_Done(iLCD_SPI_Done),
		
		.iLCD_Start_DisplayOff(rLCD_Start_DisplayOff),
		.oLCD_DisplayOff_Done(wLCD_DisplayOff_Done)
	);
	LCD_UPDATA LCD_UPDATA_inst(
		.iClk(iClk),
		.iRst_n(iRst_n),
		
		.ovLCD_SPI_TxData(wvLCD_SPI_TxData_Updata),
		.oLCD_SPI_Start(wLCD_SPI_Start_Updata),
		.oLCD_DC(wLCD_DC_Updata),
		.ivLCD_SPI_RxData(),
		.iLCD_SPI_Done(iLCD_SPI_Done),
		
		.ivDisplay_state(ivDisplay_state),
		.iMoveStop(iMoveStop),
		
		.ovColumn(wvColumn),
		.ovRow(wvRow),
		.ivFontcolor(wvFontcolor),
		.ivBGcolor(wvBGcolor),
		.ivAscii(wvAscii),
		
		.iLCD_Start_Update(rLCD_Start_Update),
		.oLCD_Update_Done(wLCD_Updata_Done)
	);
	
	FormatDisplayR90 FormatDisplayR90_inst(
	//FormatDisplayR90 FormatDisplayR90_inst(
		.iClk					(iClk),
		.iRst_n					(iRst_n),
	
		.iFKPStatus				(iComm_stateTrOut),//rvFKPStatus
	
		.ivRow					(wvRow),
		.ivColumn				(wvColumn),
	
		.ivDisplay_state		(ivDisplay_state),//
		.ivGantry				(ivGantry),	
		.ivCollimator			(ivCollimator)	,	
		.ivSwing				(ivSwing),	
		.ivMLCX					(ivMLCX),		
		.ivMLCX1				(ivMLCX1),	
		.ivMLCX2				(ivMLCX2),
		.ivJAWY					(ivJAWY),		
		.ivJAWY1				(ivJAWY1),	
		.ivJAWY2				(ivJAWY2),		
		.ivCouch_VRT			(ivCouch_VRT),	
		.ivCouch_LAT			(ivCouch_LAT),	
		.ivCouch_LNG			(ivCouch_LNG),
		.ivCouch_LNG_PLAN		(ivCouch_LNG_PLAN),
		.ovFontcolor			(wvFontcolor),
		.ovBGcolor				(wvBGcolor),
		.ovAscii(wvAscii)
	);
	LCD_RESET LCD_RESET_inst(
		.iClk(iClk),
		.iRst_n(iRst_n),

		.oRst_n(wLCD_RST)
	);
//========================================================================
	//FSM
	reg		[3:0]	state_c;
	
	always@(posedge iClk or negedge iRst_n)begin
		if(!iRst_n)begin
			state_c <= LCD_RESET;
		end
		else begin
			state_c <= rvState;
			end
		end
	
	always@(posedge iClk or negedge iRst_n)begin
			if(!iRst_n)begin
				rLCD_Start_Init <= 1'b0;
				rLCD_Start_Update <= 1'b0;
				rLCD_Start_DisplayOff <= 1'b0;
				rLCD_Start_DisplayOn <= 1'b0;
				rvState <= LCD_RESET;
				end
			else begin
				case (state_c)			//wait EPD initialize command
					LCD_RESET: begin
						rLCD_Start_Update <= 1'b0;
						rLCD_Start_DisplayOff <= 1'b0;
						rLCD_Start_DisplayOn <= 1'b0;
						if (iLCDInit) begin
							rLCD_Start_Init <= 1'b1;
							rvState <= LCD_INIT;
							end
						end
					LCD_INIT: begin			//wait EPD initialize finish
						rLCD_Start_Init <= 1'b0;
						rLCD_Start_Update <= 1'b0;
						rLCD_Start_DisplayOff <= 1'b0;
						rLCD_Start_DisplayOn <= 1'b0;
						if (wLCD_Init_Done) begin
							rvState <= LCD_WAIT;
							end
						end						
					LCD_WAIT: begin			//wait new data or power off command		
						if (iLCDDisplayOn) begin
							rLCD_Start_Init <= 1'b0;
							rLCD_Start_Update <= 1'b0;
							rLCD_Start_DisplayOff <= 1'b0;
							rLCD_Start_DisplayOn <= 1'b1;
							rvState <= LCD_DISPLAYON;
							end	
						else if (iLCDUpdate) begin
							rLCD_Start_Init <= 1'b0;
							rLCD_Start_Update <= 1'b1;
							rLCD_Start_DisplayOff <= 1'b0;
							rLCD_Start_DisplayOn <= 1'b0;
							rvState <= LCD_UPDATA;
							end
						else if (iLCDDisplayOff) begin
							rLCD_Start_Init <= 1'b0;
							rLCD_Start_Update <= 1'b0;
							rLCD_Start_DisplayOff <= 1'b1;
							rLCD_Start_DisplayOn <= 1'b0;
							rvState <= LCD_DISPLAYOFF;
							end
						end						
					LCD_DISPLAYON: begin			//update display block type stage1
						rLCD_Start_Init <= 1'b0;
						rLCD_Start_Update <= 1'b0;
						rLCD_Start_DisplayOff <= 1'b0;
						rLCD_Start_DisplayOn <= 1'b0;
						if (wLCD_DisplayOn_Done) begin
							rvState <= LCD_WAIT;
							end
						end	
					
					LCD_UPDATA: begin			//update display block type stage1
						rLCD_Start_Init <= 1'b0;
						rLCD_Start_Update <= 1'b0;
						rLCD_Start_DisplayOff <= 1'b0;
						rLCD_Start_DisplayOn <= 1'b0;
						if (wLCD_Updata_Done) begin
							rvState <= LCD_WAIT;
							end
						end	
						
					LCD_DISPLAYOFF: begin			//update display block type stage1
						rLCD_Start_Init <= 1'b0;
						rLCD_Start_Update <= 1'b0;
						rLCD_Start_DisplayOff <= 1'b0;
						rLCD_Start_DisplayOn <= 1'b0;
						if (wLCD_DisplayOff_Done) begin
							rvState <= LCD_WAIT;
							end
						end								
					default: begin
						rLCD_Start_Init <= 1'b0;
						rLCD_Start_Update <= 1'b0;
						rLCD_Start_DisplayOff <= 1'b0;
						rLCD_Start_DisplayOn <= 1'b0;
						rvState <= LCD_WAIT;
						end
					endcase
			end
		end
		
	always@(*) begin
		case(rvState)
			LCD_RESET: begin
				OLCD_RST			= wLCD_RST;
				oLCD_DC				= 1'b0;
				oLCD_CTRL			= 1'b0;				
				ovLCD_SPI_TxData	= 8'h0;
				oLCD_SPI_Start		= 1'b0;
				end
			LCD_INIT: begin				//Initialize EPD
				OLCD_RST			= 1'b1;
				oLCD_DC				= wLCD_DC_Init;
				oLCD_CTRL			= 1'b0;				
				ovLCD_SPI_TxData	= wvLCD_SPI_TxData_Init;
				oLCD_SPI_Start		= wLCD_SPI_Start_Init;
				end
			LCD_WAIT: begin
				OLCD_RST			= 1'b1;
				oLCD_DC				= 1'b0;
				oLCD_CTRL			= oLCD_CTRL;			
				ovLCD_SPI_TxData	= 8'h0;
				oLCD_SPI_Start		= 1'b0;
				end
			LCD_DISPLAYON:begin
				OLCD_RST			= 1'b1;
				oLCD_DC				= wLCD_DC_DisplayOn;
				oLCD_CTRL			= 1'b1;				
				ovLCD_SPI_TxData	= wvLCD_SPI_TxData_DisplayOn;
				oLCD_SPI_Start		= wLCD_SPI_Start_DisplayOn;
				end
			LCD_UPDATA: begin
				OLCD_RST			= 1'b1;
				oLCD_DC				= wLCD_DC_Updata;
				oLCD_CTRL			= 1'b1;				
				ovLCD_SPI_TxData	= wvLCD_SPI_TxData_Updata;
				oLCD_SPI_Start		= wLCD_SPI_Start_Updata;
				end
			LCD_DISPLAYOFF: begin
				OLCD_RST			= 1'b1;
				oLCD_DC				= wLCD_DC_DisplayOff;
				oLCD_CTRL			= 1'b0;				
				ovLCD_SPI_TxData	= wvLCD_SPI_TxData_DisplayOff;
				oLCD_SPI_Start		= wLCD_SPI_Start_DisplayOff;
				end
			default: begin
				OLCD_RST			= 1'b1;
				oLCD_DC				= 1'b0;
				oLCD_CTRL			= oLCD_CTRL;		
				ovLCD_SPI_TxData	= 8'h0;
				oLCD_SPI_Start		= 1'b0;
				end
			endcase
	end
endmodule
